import os
import pandas as pd
import numpy as np
import warnings
import seaborn as sns
from datetime import datetime
import matplotlib.pyplot as plt
# 设置 中 文 显 示 字 体
plt.rcParams['font.sans-serif']=['SimHei'] # 用 来 正 常 显 示 中 文 标 签
plt.rcParams['axes.unicode_minus']=False # 用来正常显示负号
warnings.filterwarnings("ignore") #清除警告日志

class PropertyInsuranceCostAnalyzer:
    def __init__(self):
        # 初始化数据存储
        self.policy_data = None  # 保单数据
        self.reinsurance_data = None  # 再保业务数据
        self.expense_data = None  # 费用数据
        self.reserve_data = None  # 准备金数据
        self.tax_data = None  # 税金数据
        self.indicators_data = None  # 指标数据
        self.report_dir = "insurance_reports"  # 报表保存目录

        # 创建报表目录
        if not os.path.exists(self.report_dir):
            os.makedirs(self.report_dir)

    def generate_sample_data(self, start_date="2023-01-01", end_date="2024-12-31", n=1000):
        """生成样本数据，模拟业务场景中的各项数据"""
        # 生成日期范围
        date_range = pd.date_range(start=start_date, end=end_date, freq='D')

        # 1. 保单数据
        self.policy_data = pd.DataFrame({
            "policy_id": [f"POL{str(i).zfill(6)}" for i in range(n)],
            "business_type": np.random.choice(["财险", "人身险", "再保财险", "再保人身险"], n),
            "issue_date": np.random.choice(date_range, n),
            "original_premium": np.random.uniform(1000, 100000, n).round(2),  # 原保费收入
            "written_premium": np.random.uniform(500, 80000, n).round(2)  # 分保费收入
        })

        # 2. 再保分出业务数据
        self.reinsurance_data = pd.DataFrame({
            "reins_id": [f"RE{str(i).zfill(6)}" for i in range(n)],
            "policy_id": np.random.choice(self.policy_data["policy_id"], n),
            "ceded_premium": np.random.uniform(100, 20000, n).round(2),  # 分出保费
            "recovered_reinsurance_expense": np.random.uniform(50, 10000, n).round(2)  # 摊回分保费用
        })

        # 3. 费用数据
        self.expense_data = pd.DataFrame({
            "expense_id": [f"EXP{str(i).zfill(6)}" for i in range(n)],
            "policy_id": np.random.choice(self.policy_data["policy_id"], n),
            "business_management_fee": np.random.uniform(100, 5000, n).round(2),  # 业务及管理费
            "commission": np.random.uniform(50, 3000, n).round(2),  # 手续费及佣金
            "reinsurance_fee": np.random.uniform(30, 2000, n).round(2)  # 分保费用
        })

        # 4. 准备金数据
        self.reserve_data = pd.DataFrame({
            "reserve_id": [f"RES{str(i).zfill(6)}" for i in range(n)],
            "policy_id": np.random.choice(self.policy_data["policy_id"], n),
            "claim_payment": np.random.uniform(500, 50000, n).round(2),  # 赔付支出
            "unearned_premium_reserve_extracted": np.random.uniform(200, 10000, n).round(2),  # 提取未到期责任准备金
            "unearned_premium_reserve_returned": np.random.uniform(100, 8000, n).round(2),  # 转回未到期责任准备金
            "outstanding_claims_reserve_extracted": np.random.uniform(300, 15000, n).round(2),  # 提取未决赔款准备金
            "outstanding_claims_reserve_returned": np.random.uniform(150, 12000, n).round(2)  # 转回未决赔款准备金
        })

        # 5. 税金数据
        self.tax_data = pd.DataFrame({
            "tax_id": [f"TAX{str(i).zfill(6)}" for i in range(n)],
            "policy_id": np.random.choice(self.policy_data["policy_id"], n),
            "business_tax_surcharge": np.random.uniform(50, 5000, n).round(2)  # 保险业务营业税金及附加
        })

        print("样本数据生成完成")
        return self

    def calculate_earned_premium(self, policy_row, reinsurance_row, reserve_row):
        """计算已赚保费"""
        return (policy_row["original_premium"] - reinsurance_row["ceded_premium"] -
                reserve_row["unearned_premium_reserve_extracted"] +
                reserve_row["unearned_premium_reserve_returned"])

    def calculate_indicators(self):
        """计算各项成本费用指标"""
        # 合并所有数据
        merged_data = self.policy_data.merge(self.reinsurance_data, on="policy_id", how="left")
        merged_data = merged_data.merge(self.expense_data, on="policy_id", how="left")
        merged_data = merged_data.merge(self.reserve_data, on="policy_id", how="left")
        merged_data = merged_data.merge(self.tax_data, on="policy_id", how="left")

        # 计算已赚保费
        merged_data["earned_premium"] = merged_data.apply(
            lambda row: self.calculate_earned_premium(row, row, row), axis=1
        )

        # 1. 赔付率
        merged_data["loss_ratio"] = (
                (merged_data["claim_payment"] + merged_data["outstanding_claims_reserve_extracted"] -
                 merged_data["outstanding_claims_reserve_returned"]) / merged_data["earned_premium"] * 100
        ).round(2)

        # 2. 综合费用率
        merged_data["comprehensive_expense_ratio"] = (
                (merged_data["business_management_fee"] + merged_data["commission"] +
                 merged_data["reinsurance_fee"] + merged_data["business_tax_surcharge"] -
                 merged_data["recovered_reinsurance_expense"]) / merged_data["earned_premium"] * 100
        ).round(2)

        # 3. 综合成本率
        merged_data["comprehensive_cost_ratio"] = (
                (merged_data["claim_payment"] + merged_data["outstanding_claims_reserve_extracted"] -
                 merged_data["outstanding_claims_reserve_returned"] + merged_data["business_management_fee"] +
                 merged_data["commission"] + merged_data["reinsurance_fee"] +
                 merged_data["business_tax_surcharge"] - merged_data["recovered_reinsurance_expense"]) /
                merged_data["earned_premium"] * 100
        ).round(2)

        # 4. 保费费用率
        merged_data["premium_expense_ratio"] = (
                merged_data["business_management_fee"] / merged_data["original_premium"] * 100
        ).round(2)

        # 5. 手续费及佣金比率
        merged_data["commission_ratio"] = (
                merged_data["commission"] / merged_data["original_premium"] * 100
        ).round(2)

        # 6. 分保费用比率
        merged_data["reinsurance_fee_ratio"] = (
                merged_data["reinsurance_fee"] / merged_data["written_premium"] * 100
        ).round(2)

        self.indicators_data = merged_data
        return merged_data

    def statistical_analysis(self, data=None, period="month"):
        """按周期进行统计分析"""
        if data is None:
            data = self.indicators_data

        # 确保日期列格式正确
        data["issue_date"] = pd.to_datetime(data["issue_date"])

        # 设置日期为索引
        data = data.set_index("issue_date")

        # 选择需要统计的数值列
        numeric_cols = ["loss_ratio", "comprehensive_expense_ratio", "comprehensive_cost_ratio",
                        "premium_expense_ratio", "commission_ratio", "reinsurance_fee_ratio"]

        # 按不同周期分组统计
        if period == "week":
            grouped = data[numeric_cols].resample('7D').mean()
            grouped.index = grouped.index.strftime('%Y-%m-%d')
            period_name = "七日周期"
        elif period == "month":
            grouped = data[numeric_cols].resample('M').mean()
            grouped.index = grouped.index.strftime('%Y-%m')
            period_name = "月度"
        elif period == "year":
            grouped = data[numeric_cols].resample('Y').mean()
            grouped.index = grouped.index.strftime('%Y')
            period_name = "年度"
        else:
            raise ValueError("周期参数错误，可选值：week, month, year")

        print(f"\n{period_name}指标统计（平均值）：")
        print(grouped)

        return grouped, period_name

    def plot_time_series(self, period="month"):
        """绘制时间序列趋势图"""
        grouped_data, period_name = self.statistical_analysis(period=period)

        plt.figure(figsize=(14, 10))

        # 绘制赔付率趋势
        plt.subplot(2, 2, 1)
        sns.lineplot(data=grouped_data, x=grouped_data.index, y='loss_ratio', marker='o')
        plt.title(f'{period_name}赔付率趋势')
        plt.xticks(rotation=45)
        plt.tight_layout()

        # 绘制综合费用率趋势
        plt.subplot(2, 2, 2)
        sns.lineplot(data=grouped_data, x=grouped_data.index, y='comprehensive_expense_ratio', marker='s')
        plt.title(f'{period_name}综合费用率趋势')
        plt.xticks(rotation=45)
        plt.tight_layout()

        # 绘制综合成本率趋势
        plt.subplot(2, 2, 3)
        sns.lineplot(data=grouped_data, x=grouped_data.index, y='comprehensive_cost_ratio', marker='^')
        plt.title(f'{period_name}综合成本率趋势')
        plt.xticks(rotation=45)
        plt.tight_layout()

        # 绘制各项费用率对比
        plt.subplot(2, 2, 4)
        sns.lineplot(data=grouped_data[['premium_expense_ratio', 'commission_ratio', 'reinsurance_fee_ratio']])
        plt.title(f'{period_name}各项费用率对比')
        plt.xticks(rotation=45)
        plt.legend(labels=['保费费用率', '手续费及佣金比率', '分保费用比率'])
        plt.tight_layout()

        # 保存图表
        plt.savefig(f"{self.report_dir}/{period_name}_trend_analysis.png", dpi=300, bbox_inches='tight')
        plt.show()

    def plot_business_type_comparison(self):
        """按业务类型对比各项指标"""
        if self.indicators_data is None:
            self.calculate_indicators()

        plt.figure(figsize=(16, 12))

        # 按业务类型分组计算平均值
        business_group = self.indicators_data.groupby('business_type')[
            ['loss_ratio', 'comprehensive_expense_ratio', 'comprehensive_cost_ratio',
             'premium_expense_ratio', 'commission_ratio', 'reinsurance_fee_ratio']
        ].mean().reset_index()

        # 赔付率对比
        plt.subplot(2, 3, 1)
        sns.barplot(data=business_group, x='business_type', y='loss_ratio')
        plt.title('不同业务类型的赔付率对比')
        plt.xticks(rotation=45)

        # 综合费用率对比
        plt.subplot(2, 3, 2)
        sns.barplot(data=business_group, x='business_type', y='comprehensive_expense_ratio')
        plt.title('不同业务类型的综合费用率对比')
        plt.xticks(rotation=45)

        # 综合成本率对比
        plt.subplot(2, 3, 3)
        sns.barplot(data=business_group, x='business_type', y='comprehensive_cost_ratio')
        plt.title('不同业务类型的综合成本率对比')
        plt.xticks(rotation=45)

        # 保费费用率对比
        plt.subplot(2, 3, 4)
        sns.barplot(data=business_group, x='business_type', y='premium_expense_ratio')
        plt.title('不同业务类型的保费费用率对比')
        plt.xticks(rotation=45)

        # 手续费及佣金比率对比
        plt.subplot(2, 3, 5)
        sns.barplot(data=business_group, x='business_type', y='commission_ratio')
        plt.title('不同业务类型的手续费及佣金比率对比')
        plt.xticks(rotation=45)

        # 分保费用比率对比
        plt.subplot(2, 3, 6)
        sns.barplot(data=business_group, x='business_type', y='reinsurance_fee_ratio')
        plt.title('不同业务类型的分保费用比率对比')
        plt.xticks(rotation=45)

        plt.tight_layout()
        # 保存图表
        plt.savefig(f"{self.report_dir}/business_type_comparison.png", dpi=300, bbox_inches='tight')
        plt.show()

    def plot_correlation_heatmap(self):
        """绘制指标相关性热力图"""
        if self.indicators_data is None:
            self.calculate_indicators()

        # 选择需要分析的指标列
        indicators = ['loss_ratio', 'comprehensive_expense_ratio', 'comprehensive_cost_ratio',
                      'premium_expense_ratio', 'commission_ratio', 'reinsurance_fee_ratio']

        # 计算相关系数
        corr_matrix = self.indicators_data[indicators].corr()

        # 绘制热力图
        plt.figure(figsize=(10, 8))
        mask = np.triu(np.ones_like(corr_matrix, dtype=bool))
        sns.heatmap(corr_matrix, mask=mask, annot=True, fmt=".2f", cmap='coolwarm',
                    square=True, linewidths=.5, cbar_kws={"shrink": .8})
        plt.title('各项指标相关性热力图')

        # 保存图表
        plt.savefig(f"{self.report_dir}/indicators_correlation.png", dpi=300, bbox_inches='tight')
        plt.show()

    def generate_summary_report(self):
        """生成汇总报表"""
        if self.indicators_data is None:
            self.calculate_indicators()

        print("\n====== 保险成本费用分析汇总报告 ======")
        print(f"报告生成日期: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
        print(f"数据样本量: {len(self.indicators_data)} 条保单")

        # 整体平均值
        overall_avg = self.indicators_data[
            ['loss_ratio', 'comprehensive_expense_ratio', 'comprehensive_cost_ratio',
             'premium_expense_ratio', 'commission_ratio', 'reinsurance_fee_ratio']
        ].mean().round(2)

        print("\n整体指标平均值:")
        print(f"1. 平均赔付率: {overall_avg['loss_ratio']}%")
        print(f"2. 平均综合费用率: {overall_avg['comprehensive_expense_ratio']}%")
        print(f"3. 平均综合成本率: {overall_avg['comprehensive_cost_ratio']}%")
        print(f"4. 平均保费费用率: {overall_avg['premium_expense_ratio']}%")
        print(f"5. 平均手续费及佣金比率: {overall_avg['commission_ratio']}%")
        print(f"6. 平均分保费用比率: {overall_avg['reinsurance_fee_ratio']}%")

        # 业务类型分析
        business_summary = self.indicators_data.groupby('business_type')['policy_id'].count()
        print("\n业务类型分布:")
        for business_type, count in business_summary.items():
            print(f"- {business_type}: {count} 单 ({count / len(self.indicators_data) * 100:.2f}%)")

        # 保存文本报告
        with open(f"{self.report_dir}/summary_report.txt", "w", encoding="utf-8") as f:
            f.write("====== 保险成本费用分析汇总报告 ======\n")
            f.write(f"报告生成日期: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
            f.write(f"数据样本量: {len(self.indicators_data)} 条保单\n\n")

            f.write("整体指标平均值:\n")
            f.write(f"1. 平均赔付率: {overall_avg['loss_ratio']}%\n")
            f.write(f"2. 平均综合费用率: {overall_avg['comprehensive_expense_ratio']}%\n")
            f.write(f"3. 平均综合成本率: {overall_avg['comprehensive_cost_ratio']}%\n")
            f.write(f"4. 平均保费费用率: {overall_avg['premium_expense_ratio']}%\n")
            f.write(f"5. 平均手续费及佣金比率: {overall_avg['commission_ratio']}%\n")
            f.write(f"6. 平均分保费用比率: {overall_avg['reinsurance_fee_ratio']}%\n\n")

            f.write("业务类型分布:\n")
            for business_type, count in business_summary.items():
                f.write(f"- {business_type}: {count} 单 ({count / len(self.indicators_data) * 100:.2f}%)\n")


if __name__ == "__main__":
    # 初始化分析器
    analyzer = PropertyInsuranceCostAnalyzer()

    # 生成样本数据
    analyzer.generate_sample_data(n=2000)

    # 计算指标
    analyzer.calculate_indicators()

    # 按不同周期统计并生成趋势图
    for period in ["week", "month", "year"]:
        analyzer.statistical_analysis(period=period)
        analyzer.plot_time_series(period=period)

    # 生成业务类型对比图
    analyzer.plot_business_type_comparison()

    # 生成指标相关性热力图
    analyzer.plot_correlation_heatmap()

    # 生成汇总报告
    analyzer.generate_summary_report()
    print("-----------------------------------------------")
    print("\n所有分析已完成，报表已保存至 insurance_reports 目录")
